/* Copyright 2009 Requirements Management System 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mags.remas.control;

import java.util.ArrayList;  
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.mags.common.EngineContext;
import org.mags.remas.control.commons.Cloner;
import org.mags.remas.logic.EntityLogic;
import org.mags.remas.model.entity.EntityRelationship;
import org.mags.remas.model.entity.KeyValue;
import org.mags.remas.view.commons.ImageProvider;
import org.mags.remas.view.widgets.TreeActionTransmitter;
import org.mags.remas.model.entity.ViewType;

/**
 * 
 * @author Mario Gaitan
 *
 */
public class EntityRelationshipController 
	implements ITreeContentProvider, ILabelProvider, ITableLabelProvider {
	
	public Image getImage(Object object) {
		EntityRelationship entityRelationship = (EntityRelationship)object;
		Image image = ImageProvider.getEntityImage(entityRelationship.getEntity().getEntityType().getCode().toLowerCase()+".png");		
		if(image==null)
			image = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
		return image;
	}
	public String getText(Object object) {
		EntityRelationship entityRelationship = (EntityRelationship)object;	  
		return "|"+entityRelationship.getEntity().getCode()+"| "+entityRelationship.getEntity().getName();
	}
	public void addListener(ILabelProviderListener arg0) {	
	}
	public boolean isLabelProperty(Object arg0, String arg1) {
		return false;
	}
	public void removeListener(ILabelProviderListener arg0) {
	}
	public Object getParent(Object object) {
		return null;
	}	
	protected List<Integer> getEntityTypesId(EntityRelationship relation) {
		return EntityLogic.getInstance().getEntityTypeIdByCategoryId(relation.getEntity().getEntityType().getEntityCategory().getEntityCategoryId());
	}
	public boolean hasChildren(Object object) {
		EntityRelationship relation = (EntityRelationship)object;
		return EngineContext.getDataContext().getEntityProviderFactory().getEntityRelationshipProvider().existsWithParent(relation, getEntityTypesId(relation));
	}
	public Object[] getChildren(Object object) {
		EntityRelationship relation = (EntityRelationship)object;
		return EntityLogic.getInstance().getEntityChildren(relation, getEntityTypesId(relation)).toArray();
	}	
	public Object[] getElements(Object object) {
		EntityRelationship relation = (EntityRelationship)object;
		return EntityLogic.getInstance().getEntityChildren(relation, getEntityTypesId(relation)).toArray();
	}
	public void dispose() {
	}
	public void inputChanged(Viewer viewer, Object object1, Object object2) {
	}
	public EntityRelationship refresh(EntityRelationship entityRelationship) {
		EntityRelationship er = EngineContext.getDataContext().getEntityProviderFactory().getEntityRelationshipProvider().getById(entityRelationship.getEntityRelationshipId());
		TreeActionTransmitter.getInstance().updateData(er);
		return er;
	}
	public Map<String, Object> update(EntityRelationship entityRelationship, String property, Object value) {
		EntityRelationship relationshipToEdit = Cloner.clone(entityRelationship);
		relationshipToEdit.setEntity(Cloner.clone(entityRelationship.getEntity()));
		if(property.equalsIgnoreCase("name"))
			relationshipToEdit.getEntity().setName((String)value);
		else if(property.equalsIgnoreCase("description"))
			relationshipToEdit.getEntity().setDescription((String)value);
		else if(property.equalsIgnoreCase("link")) 
			relationshipToEdit.setLink(((EntityRelationship)value).getLink());			
		EntityLogic.getInstance().update(relationshipToEdit, null);
		TreeActionTransmitter.getInstance().updateData(relationshipToEdit);
		Map<String, Object> changes = new HashMap<String, Object>();
		changes.put("entityRelationship", relationshipToEdit);
		return changes;
	}
	public Map<String, Object> update(EntityRelationship entityRelationship, List<KeyValue> keyValues) {
		EntityRelationship relationshipToEdit = Cloner.clone(entityRelationship);
		relationshipToEdit.setEntity(Cloner.clone(entityRelationship.getEntity()));
		List<KeyValue> clonedKeyValues = new ArrayList<KeyValue>();
		if(keyValues!=null)
			for(KeyValue i: keyValues)
				clonedKeyValues.add(Cloner.clone(i));		
		EntityLogic.getInstance().update(relationshipToEdit, clonedKeyValues);
		TreeActionTransmitter.getInstance().updateData(relationshipToEdit);
		Map<String, Object> changes = new HashMap<String, Object>();
		changes.put("entityRelationship", relationshipToEdit);
		if(keyValues!=null)
			changes.put("keyValues", clonedKeyValues);
		return changes;
	}	
	public Map<String, Object> create(EntityRelationship entityRelationship, EntityRelationship parentEntityRelationship) {
		return this.create(entityRelationship, parentEntityRelationship, null);
	}
	public Map<String, Object> create(EntityRelationship entityRelationship, EntityRelationship parentEntityRelationship, List<KeyValue> keyValues) {
		entityRelationship.getEntity().setEntityStatus(EngineContext.getDataContext().getEntityProviderFactory().getEntityStatusProvider().getActiveStatus());
		EntityRelationship entityRelationshipToCreate = Cloner.clone(entityRelationship);
		entityRelationshipToCreate.setEntity(Cloner.clone(entityRelationshipToCreate.getEntity()));
		List<KeyValue> clonedKeyValues = new ArrayList<KeyValue>();
		if(keyValues!=null)
			for(KeyValue i: keyValues)
				clonedKeyValues.add(Cloner.clone(i));
		EntityLogic.getInstance().create(entityRelationshipToCreate, parentEntityRelationship, clonedKeyValues);
		ViewType viewType = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationship.getEntity().getEntityType().getEntityTypeId(), parentEntityRelationship.getEntity().getEntityType().getEntityTypeId()).getViewType();
		TreeActionTransmitter.getInstance().addItem(entityRelationshipToCreate, parentEntityRelationship, viewType);
		List<EntityRelationship> childs = EntityLogic.getInstance().getEntityChildren(parentEntityRelationship, EntityLogic.getInstance().getEntityTypeIdByCategoryIdAndViewTypeId(parentEntityRelationship.getEntity().getEntityType().getEntityCategory().getEntityCategoryId(), viewType.getViewTypeId()));
		for(EntityRelationship child: childs)
			TreeActionTransmitter.getInstance().updateData(child);
		Map<String, Object> changes = new HashMap<String, Object>();
		changes.put("entityRelationship", entityRelationshipToCreate);
		if(keyValues!=null)
			changes.put("keyValues", clonedKeyValues);		
		return changes;
	}	
	public void delete(List<EntityRelationship> relationshipsToDelete) {
		for(EntityRelationship entityRelationshipToDelete: relationshipsToDelete) {
			EntityRelationship parentEntityRelationship = entityRelationshipToDelete.getParent();
			EntityLogic.getInstance().delete(entityRelationshipToDelete, parentEntityRelationship, entityRelationshipToDelete.getEntity().getEntityType().getEntityCategory());
			TreeActionTransmitter.getInstance().removeItem(entityRelationshipToDelete);
				ViewType viewType = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationshipToDelete.getEntity().getEntityType().getEntityTypeId(), entityRelationshipToDelete.getEntityParent().getEntityType().getEntityTypeId()).getViewType();
				List<EntityRelationship> childs = EntityLogic.getInstance().getEntityChildren(parentEntityRelationship, EntityLogic.getInstance().getEntityTypeIdByCategoryIdAndViewTypeId(entityRelationshipToDelete.getEntity().getEntityType().getEntityCategory().getEntityCategoryId(), viewType.getViewTypeId()));
				for(EntityRelationship child: childs)
					TreeActionTransmitter.getInstance().updateData(child);
		}		
	}	
	public void copy(List<EntityRelationship> entityRelationshipList, EntityRelationship parentEntityRelationship) {
		List<EntityRelationship> newEntityRelationshipList = new ArrayList<EntityRelationship>();
		for(EntityRelationship entityRelationship: entityRelationshipList) {
			EntityRelationship entityRelationshipToCopy = Cloner.clone(entityRelationship);
			entityRelationship.setEntity(Cloner.clone(entityRelationship.getEntity()));
			newEntityRelationshipList.add(entityRelationshipToCopy);
		}
		EntityLogic.getInstance().create(newEntityRelationshipList, parentEntityRelationship);
		for(EntityRelationship entityRelationship: newEntityRelationshipList) {
			ViewType viewType = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationship.getEntity().getEntityType().getEntityTypeId(), parentEntityRelationship.getEntity().getEntityType().getEntityTypeId()).getViewType();
			TreeActionTransmitter.getInstance().addItem(entityRelationship, parentEntityRelationship, viewType);
		}
		TreeActionTransmitter.getInstance().refreshItem(parentEntityRelationship);
	}
	public void referenceTo(List<EntityRelationship> entityRelationshipList, EntityRelationship reference) {
		EntityLogic.getInstance().referenceTo(entityRelationshipList, reference);
	}	
	public void referenceFrom(List<EntityRelationship> entityRelationshipList, EntityRelationship reference) {
		EntityLogic.getInstance().referenceFrom(entityRelationshipList, reference);
	}
	public void move(List<EntityRelationship> entityRelationshipList, EntityRelationship newParentEntityRelationship) {
		List<EntityRelationship> newEntityRelationshipList = new ArrayList<EntityRelationship>();
		boolean isChild = false;
		for(EntityRelationship entityRelationship: entityRelationshipList) {
			isChild = false;
			for(EntityRelationship oEntityRelationship: entityRelationshipList) {
				if(entityRelationship.getEntity().getEntityId()!=oEntityRelationship.getEntity().getEntityId())
					if(entityRelationship.getHierarchicalPath().startsWith(oEntityRelationship.getHierarchicalPath())) {
						isChild = true;
						break;
					}
			}
			if(!isChild)
				newEntityRelationshipList.add(entityRelationship);
		}
		for(EntityRelationship entityRelationship: newEntityRelationshipList) {
			EntityRelationship entityRelationshipToMove = Cloner.clone(entityRelationship);
			EntityRelationship currentParentEntityRelationship = entityRelationship.getParent();
			EntityLogic.getInstance().changeParent(entityRelationshipToMove, newParentEntityRelationship, currentParentEntityRelationship, entityRelationship.getEntity().getEntityType().getEntityCategory());
			TreeActionTransmitter.getInstance().removeItem(entityRelationship);
			ViewType viewType = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationshipToMove.getEntity().getEntityType().getEntityTypeId(), newParentEntityRelationship.getEntity().getEntityType().getEntityTypeId()).getViewType();
			TreeActionTransmitter.getInstance().addItem(entityRelationshipToMove, newParentEntityRelationship, viewType);
			List<EntityRelationship> childs = EntityLogic.getInstance().getEntityChildren(newParentEntityRelationship, EntityLogic.getInstance().getEntityTypeIdByCategoryId(entityRelationship.getEntity().getEntityType().getEntityCategory().getEntityCategoryId()));
			for(EntityRelationship child: childs)
				TreeActionTransmitter.getInstance().updateData(child);
			childs = EntityLogic.getInstance().getEntityChildren(currentParentEntityRelationship, EntityLogic.getInstance().getEntityTypeIdByCategoryId(entityRelationship.getEntity().getEntityType().getEntityCategory().getEntityCategoryId()));
			for(EntityRelationship child: childs)
				TreeActionTransmitter.getInstance().updateData(child);
			newParentEntityRelationship = EngineContext.getDataContext().getEntityProviderFactory().getEntityRelationshipProvider().getByIdWithProperties(newParentEntityRelationship.getEntityRelationshipId());
			if(newParentEntityRelationship!=null)
				TreeActionTransmitter.getInstance().updateData(newParentEntityRelationship);
		}
	}
	public void moveAbove(List<EntityRelationship> entityRelationshipList, EntityRelationship referenceEntityRelationship) {
		EntityRelationship entityRelationshipToMove = entityRelationshipList.get(0);
		EntityRelationship parentEntityRelationship = entityRelationshipToMove.getParent();
		entityRelationshipToMove = Cloner.clone(entityRelationshipToMove);
		if(referenceEntityRelationship.getPosition()>entityRelationshipToMove.getPosition())
			EntityLogic.getInstance().movePositionUp(entityRelationshipToMove, referenceEntityRelationship, parentEntityRelationship, Boolean.TRUE);
		else if(referenceEntityRelationship.getPosition()+1<entityRelationshipToMove.getPosition())
			EntityLogic.getInstance().movePositionDown(entityRelationshipToMove, referenceEntityRelationship, parentEntityRelationship, Boolean.FALSE);
		else
			throw new RuntimeException("init position and end position can't be the same one");
		TreeActionTransmitter.getInstance().refreshParent(referenceEntityRelationship);
	}
	public void moveBelow(List<EntityRelationship> entityRelationshipList, EntityRelationship referenceEntityRelationship) {
		EntityRelationship entityRelationshipToMove = entityRelationshipList.get(0);
		EntityRelationship parentEntityRelationship = entityRelationshipToMove.getParent();
		entityRelationshipToMove = Cloner.clone(entityRelationshipToMove);		
		if(referenceEntityRelationship.getPosition()-1>entityRelationshipToMove.getPosition())
			EntityLogic.getInstance().movePositionUp(entityRelationshipToMove, referenceEntityRelationship, parentEntityRelationship, Boolean.FALSE);
		else if(referenceEntityRelationship.getPosition()<entityRelationshipToMove.getPosition())
			EntityLogic.getInstance().movePositionDown(entityRelationshipToMove, referenceEntityRelationship, parentEntityRelationship, Boolean.TRUE);
		else
			throw new RuntimeException("init position and end position can't be the same one");
		TreeActionTransmitter.getInstance().refreshParent(referenceEntityRelationship);
	}
	public Image getColumnImage(Object element, int columnIndex) {
		if(columnIndex==0) {
			EntityRelationship entityRelationship = (EntityRelationship)element;
			Image image = ImageProvider.getEntityImage(entityRelationship.getEntity().getEntityType().getCode().toLowerCase()+".png");		
			if(image==null)
				image = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
			return image;			
		} else if (columnIndex==2) {
			EntityRelationship entityRelationship = (EntityRelationship)element;
			if(entityRelationship.getLink()!=null) {
				Image image = ImageProvider.getEntityImage(entityRelationship.getLink().getEntity().getEntityType().getCode().toLowerCase()+".png");		
				if(image==null)
					image = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
				return image;
			} else
				return null;
		}
		return null;
	}
	public String getColumnText(Object element, int columnIndex) {
		EntityRelationship entityRelationship = (EntityRelationship)element;
		if(columnIndex==0)
			return entityRelationship.getEntity().getCode() + ")     " + entityRelationship.getEntity().getName();
		else
		if(columnIndex==1)
			return (entityRelationship.getEntity().getDescription()!=null)?entityRelationship.getEntity().getDescription():"";
		else
		if(columnIndex==2) {
			if(entityRelationship.getLink()!=null) {
				EntityRelationship link = (EntityRelationship)entityRelationship.getLink();
				return link.getEntity().getCode()+")"+link.getEntity().getName();
			} else
				return "";
		}
		return null;
	}
}
